package com.daji.concurrency.multithread_fundamental;

public class A04_Interrupt2_Volatile {
    public static void main(String[] args) throws InterruptedException {
        //仍然不能用这种方式
        /*new Thread(()->{
            System.out.println(1);
        }).start();*/

        HelloThread t = new HelloThread();
        t.start();
        Thread.sleep(1);
        t.running = false; // 标志位置为false
    }
}

class HelloThread extends Thread {
    //另一个常用的中断线程的方法是设置标志位。我们通常会用一个running标志位来标识线程是否应该继续运行
    //注意到HelloThread的标志位boolean running是一个线程间共享的变量。
    // 线程间共享变量需要使用volatile(adj. 易变的,不稳定的)关键字标记，确保每个线程都能读取到更新后的变量值。
    //volatile(adj. 易变的,不稳定的)
    /*
        关于volatile：
        volatile的作用是作为指令关键字，确保本条指令不会因编译器的优化而省略，且要求每次直接读值。
        volatile的变量是说这变量可能会被意想不到地改变，这样，编译器就不会去假设这个变量的值了。
        精确地说就是，编译器在用到这个变量时必须每次都小心地重新读取这个变量的值，而不是使用保存在寄存器里的备份。
    */
    /*
        具体到Java多线程环境中的应用：
        为什么要对线程间共享的变量用关键字volatile声明？这涉及到Java的内存模型。
        在Java虚拟机中，变量的值保存在主内存中，但是，当线程访问变量时，它会先获取一个副本，并保存在自己的工作内存中。
        如果线程修改了变量的值，虚拟机会在某个时刻把修改后的值回写到主内存，但是，这个时间是不确定的！

        这会导致如果一个线程更新了某个变量，另一个线程读取的值可能还是更新前的。
        例如，主内存的变量a = true，线程1执行a = false时，
        它在此刻仅仅是把变量a的副本变成了false，主内存的变量a还是true，
        在JVM把修改后的a回写到主内存之前，其他线程读取到的a的值仍然是true，这就造成了多线程之间共享的变量不一致。

        因此，volatile关键字的目的是告诉虚拟机：
            * 每次访问变量时，总是获取主内存的最新值；
            * 每次修改变量后，立刻回写到主内存。
        volatile关键字解决的是可见性问题：当一个线程修改了某个共享变量的值，其他线程能够立刻看到修改后的值。
    */
    /*
        volatile
        多线程的原子性、可见性、有序性 **（花3分钟过一下 很简单）：**
        https://zhuanlan.zhihu.com/p/142929863
    */
    public volatile boolean running = true;

    public void run() {
        int n = 0;
        while (running) {
            n++;
            System.out.println(n + " hello!");
        }
        System.out.println("end!");
    }
}


